import os
import six
import requests


EOP_TOKEN = 'Token'


class ResourceNotUrlException(Exception):

    pass


def add_json_content_type_to_header(func):
    def decorate(*args, **kwargs):
        headers = kwargs.pop('headers', dict())
        content_type = headers.get('content-type', 'application/json')
        headers['content-type'] = content_type
        kwargs['headers'] = headers
        return func(*args, **kwargs)
    return decorate


def add_auth_token_to_header(func):
    def decorate(*args, **kwargs):
        headers = kwargs.pop('headers', dict())

        token = kwargs.pop(EOP_TOKEN, None)
        if token:
            headers['Authorization'] = 'Token {}'.format(token)
        kwargs['headers'] = headers
        return func(*args, **kwargs)
    return decorate


def add_auth_token_to_kwargs_from_env(func):
    def decorate(*args, **kwargs):
        if not kwargs.get(EOP_TOKEN) and os.environ.get(EOP_TOKEN, None):
            kwargs[EOP_TOKEN] = os.environ.get(EOP_TOKEN)
        return func(*args, **kwargs)
    return decorate


class HttpClient(object):

    def __init__(self, root, debug=False):
        self.root = root
        self.debug = debug

    @add_auth_token_to_header
    @add_json_content_type_to_header
    def get(self, url, **kwargs):
        params = kwargs.pop('params', dict())
        return requests.get(url, params, **kwargs)

    @add_auth_token_to_header
    @add_json_content_type_to_header
    def post(self, url, data, **kwargs):
        return requests.post(url, data, **kwargs)

    @add_auth_token_to_header
    @add_json_content_type_to_header
    def put(self, url, data, **kwargs):
        return requests.put(url, data, **kwargs)

    @add_auth_token_to_header
    @add_json_content_type_to_header
    def delete(self, url, **kwargs):
        return requests.delete(url, **kwargs)


class Resource(object):

    _url_path = None

    def __init__(self, *args, **kwargs):
        for k, v in six.iteritems(kwargs):
            setattr(self, k, v)

    def to_dict(self, exclude_atts=None):
        exclude_atts = exclude_atts or []

        attrs = list(self.__dict__.keys())
        attrs = [attr for attr in attrs if not attr.startswith('_')
                and attr not in exclude_atts]
        return {attr: getattr(self, attr, None) for attr in attrs}

    @classmethod
    def get_url(cls):
        if cls._url_path is not None:
            return cls._url_path
        raise ResourceNotUrlException("class {} url_path is None".format(cls.__name__))


class ResourceManager(object):

    def __init__(self, resource, endpoint, debug=False):
        self.resource = resource
        self.debug = debug
        self.client = HttpClient(endpoint, debug)

    @staticmethod
    def handler_error(response):
        try:
            content = response.json()
            fault = content.get('faultstring', '') if content else ''
            if fault:
                response.reason += '\nMESSAGE: %s' % fault
        except Exception as e:
            response.reason += ('\nUnable to retrieve detailed message '
                                'from the HTTP response. %s\n' % str(e))
        response.raise_for_status()

    def handler_response(self, response):
        if response.status_code <= requests.codes.bad_request:
            self.handler_error(response)
        if response.text == "":
            return {'status': True}
        return response.json()

    @add_auth_token_to_kwargs_from_env
    def detail(self, rid, **kwargs):
        url = '/{}/{}'.format(self.resource.get_url(), rid)
        response = self.client.get(url, **kwargs)
        return self.handler_response(response)

    @add_auth_token_to_kwargs_from_env
    def create(self, data, **kwargs):
        url = '/{}'.format(self.resource.get_url())
        response = self.client.post(url, data, **kwargs)
        return self.handler_response(response)

    @add_auth_token_to_kwargs_from_env
    def delete(self, rid, **kwargs):
        url = '/{}/{}'.format(self.resource.get_url(), rid)
        response = self.client.post(url, **kwargs)
        return self.handler_response(response)

    @add_auth_token_to_kwargs_from_env
    def list(self, **kwargs):
        url = '/{}'.format(self.resource.get_url())
        response = self.client.get(url, **kwargs)
        return self.handler_response(response)


class Client(object):

    def __init__(self, base_url, api_url=None, api_version=None, token=None, debug=False):

        api = [v for v in (base_url, api_url, api_version) if v]
        api = 'http://{}'.format('/'.join(api))

        self.api = api
        self.debug = debug
        self.token = token
        self.managers = dict()

        if self.token:
            os.environ[EOP_TOKEN] = token
        self.setup()

    def setup(self):
        pass
